<?php


class UploadService extends TP_Service {
    private  $tmpDir = "upload/files_tmp"; //分片临时文件目录
    private  $saveDir = "upload/files"; //文件最终保存目录
	private $client;

    public function __construct() {
        parent::__construct();
        $this->load->model("SModel/File_model");
        $this->load->model("SModel/Pattern_model");
		$this->load->library('ProjectService/PicThumb');
		$this->client = new Yar_Client($this->config->item('rpc')['url']);
    }




    public function upload($param) {
        if (!empty($_FILES)) {
            $in = @fopen($_FILES["file"]["tmp_name"], "rb");
            if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
                exit(retJson(ErrCode::ErrCode_10007));
            }
        } else {
            if (!$in = @fopen("php://input", "rb")) {
                exit(retJson(ErrCode::ErrCode_10007));
            }
        }
        // var_dump($param);
        if ($param['totalChunks'] == 1) {
            //如果只有1片，则不需要合并，直接将临时文件转存到保存目录下
            $filename = $param['filename'];
            $saveDir = $this->saveDir . '/' . date('Y-m-d');
            if (!is_dir($saveDir)) {
                @mkdir($saveDir, 755);
            }

            $uploadPath = $saveDir . '/' . $filename;
            $res['merge'] = false;


            $type = explode('.',$filename)['1'];
            $arr = [
                'filename' => $filename,
                'filesize' => $param['totalSize'],
                'md5'      => $param['identifier'],
                'type'     => $type,
                'filepath' => $uploadPath
            ];
            $this->md5fileSave($arr);

        $this->addPatternImg(['filename' =>  $filename ,'filepath' => $uploadPath]);


        } else { //需要合并

            $filePath = $this->tmpDir . '/' . $param['identifier']; //临时分片文件路径
            $uploadPath = $filePath . '_' . $param['chunkNumber']; //临时分片文件名
            $res['merge'] = true;
        }
        if (!$out = @fopen($uploadPath, "wb")) {
            exit(retJson(ErrCode::ErrCode_11001));
            // return $this->message(1004, '文件不可写');
        }

        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }
        @fclose($in);
        @fclose($out);

        $res['code'] = 0;
        return $res;
    }



    public function merge($param) {

        $filePath = $this->tmpDir . '/' .$param['identifier'];

        $totalChunks = $param['totalChunks']; //总分片数
        $filename = $param['filename']; //文件名


        $totalSize = $param['totalSize'];




        $type = explode('.',$filename)['1'];

        $done = true;
        //检查所有分片是否都存在
        for ($index = 1; $index <= $totalChunks; $index++) {
            if (!file_exists("{$filePath}_{$index}")) {
                $done = false;
                break;
            }
        }
        if ($done === false) {
            exit(retJson(ErrCode::ErrCode_11002));
        }
        //如果所有文件分片都上传完毕，开始合并
        $timeStart = $this->getmicrotime(); //合并开始时间
        $saveDir = $this -> saveDir . '/' . date('Y-m-d');
        if (!is_dir($saveDir)) {
            @mkdir($saveDir);
        }

        $uploadPath = $saveDir . '/' . $filename;

        if (!$out = @fopen($uploadPath, "wb")) {
            exit(retJson(ErrCode::ErrCode_11001));
        }
        if (flock($out, LOCK_EX)) { // 进行排他型锁定
            for ($index = 1; $index <= $totalChunks; $index++) {
                if (!$in = @fopen("{$filePath}_{$index}", "rb")) {
                    break;
                }
                while ($buff = fread($in, 4096)) {
                    fwrite($out, $buff);
                }
                @fclose($in);
                @unlink("{$filePath}_{$index}"); //删除分片
            }

            flock($out, LOCK_UN); // 释放锁定
        }
        @fclose($out);
        $timeEnd = $this->getmicrotime(); //合并完成时间

        $res['code'] = 0;
        $res['time'] = $timeEnd - $timeStart; //合并总耗时


        //保存文件信息 md5唯一标识
        $arr = [
            'filename' => $filename,
            'filesize' => $totalSize,
            'md5'      => $param['identifier'],
            'type'     => $type,
            'filepath' => $uploadPath
        ];
        $this->md5fileSave($arr);




        $this->addPatternImg(['filename' =>  $filename ,'filepath' => $uploadPath]);

        return $res;
    }



    //计算时间
    private function getmicrotime()
    {
        list($usec, $sec) = explode(" ",microtime());
        return ((float)$usec + (float)$sec);
    }


    public function checkFile($param)
    {
        if(!isset(
            $param['totalSize'],
            $param['identifier'],
            $param['totalChunks']
        )){
            exit(retJson(ErrCode::ErrCode_10002));
        }

//        $rs = $this->checkMd5($param);
//        if ($rs['isExist'] == true) {
//            $this->addPatternImg(['filename' =>  $param['filename'] ,'filepath' => $rs['filepath']]);
//            return $rs;
//        }

        $identifier = $param['identifier'];
        $filePath = $this -> tmpDir. '/' . $identifier; //临时分片文件路径
        $totalChunks = $param['totalChunks'];



        //检查分片是否存在
        $chunkExists = [];
        for ($index = 1; $index <= $totalChunks; $index++ ) {
            if (file_exists("{$filePath}_{$index}")) {
                array_push($chunkExists, $index);
            }
        }


        if (count($chunkExists) == $totalChunks) { //全部分片存在，则直接合成
            $this->merge($param);
        } else {
            $res['uploaded'] = $chunkExists;
            return $res;
        }
    }




    public function md5fileSave($param){
        if(!isset(
            $param['filename'],
            $param['filesize'],
            $param['md5'],
            $param['type'],
            $param['filepath']
        )){
            exit(retJson(ErrCode::ErrCode_10002));
        }


        $add = [
            'filename' => $param['filename'],
            'filesize' => $param['filesize'],
            'md5' => $param['md5'],
            'type' => $param['type'],
            'filepath' => $param['filepath'],
        ];


        $this->File_model->add($add);
        return true;
    }



    //检测md5表是否已存在该文件

    private function checkMd5($param){
        $file = $this->File_model->get_single(['md5' => $param['identifier'] , 'filesize' => $param['totalSize']]);
        if(!empty($file)){
            $res['isExist'] = true;
            $res['filepath'] = $file['filepath'];
        }else{
            $res['isExist'] = false;
        }
        return $res;
    }




    private function addPatternImg($param){
        if(!isset($param['filename'],$param['filepath'])){
            exit(retJson(ErrCode::ErrCode_10002));
        }

        $files = explode('.',$param['filename']);

        $imgtype = strstr($files['0'], '-');

        if ($imgtype) {
            $result = substr($files['0'], 0, strripos($files['0'], "-"));
        } else {
            $result = $files['0'];
        }

        $this->db->trans_start();
        $sql = sql_format("SELECT pid,picture,otherImg FROM tp_pattern WHERE no = '{0}' FOR UPDATE", $result);
        $info = $this->Pattern_model->single($sql);
        if($info){
            if($imgtype){
                $update = array(
                    'otherImg' =>   empty($info->otherImg) ? $param['filepath'] : $info->otherImg . ','.$param['filepath']
                );
                $this->Pattern_model->update($update,['no' => $result]);

            }else{
                $update = array(
                    'picture' =>   $param['filepath']
                );

				// 生成缩略图
				// 按比例生成缩略图
				$option = array(
					'type' => 'crop',
					'width' => 330,
					'height' => 240,
					'handler' => 'gd'
				);

				// 源图
				$source1 = $param['filepath'];
				$path_arr = explode('.', $param['filepath']);
				$dest1 = $path_arr[0] . '_thumb.' . $path_arr[1];
				$thumb = new PicThumb();
				$thumb->set_config($option);
				$thumb->create_thumb($source1, $dest1);
				$update['picture_thumb'] = $dest1;

                $this->Pattern_model->update($update,['no' => $result]);
            }

			$this->client->updateIndex($info->pid);
        }

        $this->db->trans_complete();
    }
}
